package main;

import java.awt.geom.Point2D;
import java.util.ArrayList;

/**
 * This class keeps track collisions among objects. We use post collision
 * detection which means we detect collision after object collided; Therefore,
 * this class also responsible for updating objects position.
 * 
 * @author Leo
 * 
 */
public class CollisonDetector {
    /** Store all ICollider objects. */
    private ArrayList<ICollider> collsionObjectsArrayList;

    /**
     * Default Constructor.
     */
    public CollisonDetector() {
        collsionObjectsArrayList = new ArrayList<ICollider>();
    }

    /**
     * Save objects position before update their position.
     */
    public final void saveLastPosition() {
        for (ICollider item : collsionObjectsArrayList) {
            item.saveLastPosition();
        }
    }

    /**
     * Test if tow object collide with each other.
     *
     * @param first
     *            is the first object
     * @param second
     *            is the second object
     * @return true if they collide.
     */
    private boolean isCollide(final ICollider first, final ICollider second) {
        Point2D firstMax = first.getMax();
        Point2D firstMin = first.getMin();
        Point2D secondMax = second.getMax();
        Point2D secondMin = second.getMin();
        return !(firstMin.getX() > secondMax.getX()
                || firstMax.getX() < secondMin.getX()
                || firstMin.getY() > secondMax.getY()
                || firstMax.getY() < secondMin.getY());
    }

    /**
     * Add object to collision detection system.
     *
     * @param collider
     *            will be put in collision detection
     * @return the number of objects in system
     */
    public final int addObject(final ICollider collider) {
        collsionObjectsArrayList.add(collider);
        return collsionObjectsArrayList.size();
    }

    /**
     * Remove all colliders.
     */
    public final void clearAllObjects() {
        collsionObjectsArrayList.clear();
    }

    /**
     * O(n^2) Collision detection algorithm.
     *
     * @return a list of collision pair. The first element in a pair is the fast
     *         one.
     */
    public final ArrayList<Pair> doCollision() {
        Point2D zero = new Point2D.Float(0, 0);
        ArrayList<Pair> collidePairArrayList = new ArrayList<Pair>();
        for (ICollider colliderA : collsionObjectsArrayList) {
            for (ICollider colliderB : collsionObjectsArrayList) {
                // Test if two objects are collide. Also, we want to make
                // sure each collision only add once in collision list.
                if (colliderA.getSpeed().distance(zero) > colliderB.getSpeed()
                        .distance(zero)
                        && isCollide(colliderA, colliderB)) {
                    Pair twoObjectsPair = new Pair(colliderA, colliderB);
                    collidePairArrayList.add(twoObjectsPair);
                }
            }
        }
        return collidePairArrayList;
    }

    /**
     * Update objects position according to timeDelta.
     *
     * @param timeDelta
     *            is the millisecond form last frame
     */
    public final void updateAllPosition(final float timeDelta) {
        for (ICollider objCollider : collsionObjectsArrayList) {
            Point2D nextPos = objCollider.calculateNextPosition(timeDelta);
            objCollider.setPosition(nextPos);
        }
    }

    /**
     * Remove collider object from system.
     *
     * @param collider
     *            is the object that will be removed
     * @return number of colliders left in the system.
     */
    public final int removeObject(final ICollider collider) {
        for (int i = 0; i < collsionObjectsArrayList.size(); i++) {
            ICollider arrayElement = collsionObjectsArrayList.get(i);
            if (arrayElement.equals(collider)) {
                collsionObjectsArrayList.remove(collider);
                break;
            }
        }
        return collsionObjectsArrayList.size();
    }

    /**
     * Number of colliders in system.
     *
     * @return size of collider arraylist
     */
    public final int size() {
        return collsionObjectsArrayList.size();
    }

}
